iT邦幫忙

2023 iThome 鐵人賽

DAY 10
0
Software Development

當rust 遇上 cqrs & es系列 第 10

D10 處理2個aggregate

  • 分享至 

  • xImage
  •  

先前把reader和book拆為2個aggregate,但一個交易會同時影響2個aggregate。這邊試著用另一個function處理(domain service?):

準備command:

pub enum ReaderBookCommand {
    BorrowBook {
        book_id: String,
        reader_id: String,
        borrow_date: DateTime<Utc>,
        due_date: DateTime<Utc>,

    },
    ReturnBook {
        book_id: String,
        reader_id: String,
        return_date: DateTime<Utc>,
    },
}

handler,同時輸入兩個store:

pub async fn handle_reader_book_command(
    reader_store: &impl EventStore<Reader>,
    book_store: &impl EventStore<Book>,
    reader_service: &ReaderService,
    book_service: &BookService,
    command: ReaderBookCommand,
) -> Result<(), ReaderBookError> {
    match command {
        ReaderBookCommand::BorrowBook { book_id, reader_id, borrow_date, due_date } => {
            todo!()
        }
        ReaderBookCommand::ReturnBook { book_id, reader_id, return_date } => {
            todo!()
        }
    }
    Ok(())

借書command處理,先取書再給reader,兩個aggregate皆handle成功才會commit:

ReaderBookCommand::BorrowBook {
    book_id, reader_id, borrow_date, due_date
} => {
    let book_context = book_store.load_aggregate(&book_id).await?;
    let book = book_context.aggregate();
    let reader_context = reader_store.load_aggregate(&reader_id).await?;
    let reader = reader_context.aggregate();

    let book_events = book.handle(
        BookCommand::LendBook(LendingRecord {
            reader_id,
            lent_date: borrow_date,
            due_date,
        }),
        book_service).await?;          // 檢核錯誤會回傳error
    let reader_events = reader.handle(
        ReaderCommand::BorrowBook {
            book_id,
            due_date,
            borrowed_date: borrow_date,
        },
        reader_service).await?;        // 檢核錯誤會回傳 error
    book_store.commit(book_events, book_context, Default::default()).await?;
    reader_store.commit(reader_events, reader_context, Default::default()).await?;
}

還書command處理:

ReaderBookCommand::ReturnBook { book_id, reader_id, return_date } => {
    let book_context = book_store.load_aggregate(&book_id).await?;
    let book = book_context.aggregate();
    let reader_context = reader_store.load_aggregate(&reader_id).await?;
    let reader = reader_context.aggregate();

    let reader_events = reader.handle(
        ReaderCommand::ReturnBook {
            book_id,
            return_date: return_date.clone(),
        },
        reader_service).await?;
    let lent_record = book.lending_records.iter()
        .find(|lent_record| lent_record.reader_id == reader_id).unwrap();
    let book_events = book.handle(
        BookCommand::ReturnBook(LentRecord {
            reader_id: lent_record.reader_id.clone(),
            lent_date: lent_record.lent_date,
            due_date: lent_record.due_date,
            returned_date: Some(return_date),
        }),
        book_service).await?;
    reader_store.commit(reader_events, reader_context, Default::default()).await?;
    book_store.commit(book_events, book_context, Default::default()).await?;
}

上一篇
D9 測試 reader event store
下一篇
D11 service testing
系列文
當rust 遇上 cqrs & es30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言